package cn.baker.delayqueue.config;


import cn.baker.delayqueue.init.RedisDelayQueueRunner;
import cn.baker.delayqueue.mapper.DelayQueueMessageMapper;
import cn.baker.delayqueue.service.RedisDelayQueueHandle;
import cn.baker.delayqueue.task.ScanTask;
import cn.baker.delayqueue.util.RedisDelayQueueUtil;
import cn.hutool.core.lang.Assert;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Throwables;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;

import java.util.List;

/**
 *
 * @author yuanyu
 */
@Slf4j
@Configuration
@EnableScheduling
@EnableConfigurationProperties({DelayQueueProperties.class, RedisProperties.class})
public class DelayQueueConfig {

    private final String REDISSON_PREFIX = "redis://";

    @Bean("redissonClient")
    @ConditionalOnMissingBean(RedissonClient.class)
    RedissonClient redissonClient(RedisProperties redisProperties) {
        Config config = new Config();
        String url = REDISSON_PREFIX + redisProperties.getHost() + ":" + redisProperties.getPort();
        // 这里以单台redis服务器为例
        config.useSingleServer()
                .setAddress(url)
                .setPassword(redisProperties.getPassword())
                .setDatabase(redisProperties.getDatabase())
                .setPingConnectionInterval(1000);
        config.setLockWatchdogTimeout(10000L);
        try {
            return Redisson.create(config);
        } catch (Exception e) {
            log.error("redissonClient init redis url:[{}], e={}", url, Throwables.getStackTraceAsString(e));
            return null;
        }
    }



    @Bean("serializeObjectMapper")
    ObjectMapper objectMapper() {
        // 序列化包括类型描述 否则反向序列化实体会报错，一律都为JsonObject
        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapper.activateDefaultTyping(mapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
        return mapper;
    }

    @Bean("delayQueueMessageMapper")
    DelayQueueMessageMapper delayQueueMessageMapper(JdbcTemplate jdbcTemplate, DelayQueueProperties delayQueueProperties) {
        return new DelayQueueMessageMapper(jdbcTemplate, delayQueueProperties);
    }

    @Bean("redisDelayQueueUtil")
    RedisDelayQueueUtil redisDelayQueueUtil(@Qualifier("redissonClient") RedissonClient redissonClient, @Qualifier("delayQueueMessageMapper") DelayQueueMessageMapper delayQueueMessageMapper, @Qualifier("serializeObjectMapper") ObjectMapper objectMapper, DelayQueueProperties delayQueueProperties) {
        return new RedisDelayQueueUtil(redissonClient, delayQueueMessageMapper, objectMapper, delayQueueProperties);
    }


    @Bean
    RedisDelayQueueRunner redisDelayQueueRunner(@Qualifier("redisDelayQueueUtil") RedisDelayQueueUtil redisDelayQueueUtil, List<RedisDelayQueueHandle> redisDelayQueueHandleList, @Qualifier("serializeObjectMapper") ObjectMapper objectMapper, DelayQueueProperties delayQueueProperties) {
        Assert.notEmpty(redisDelayQueueHandleList, "RedisDelayQueueHandle实现类不能为空～～～");
        return new RedisDelayQueueRunner(redisDelayQueueUtil, redisDelayQueueHandleList, objectMapper, delayQueueProperties);
    }


    @Bean
    ScanTask scanTask(@Qualifier("redisDelayQueueUtil") RedisDelayQueueUtil redisDelayQueueUtil, @Qualifier("delayQueueMessageMapper") DelayQueueMessageMapper delayQueueMessageMapper, DelayQueueProperties delayQueueProperties) {
        return new ScanTask(redisDelayQueueUtil, delayQueueMessageMapper, delayQueueProperties);
    }


}
